#include "log.hpp"
#include <mutex>
#include <condition_variable>
#include <queue>
#include <thread>
#include <functional>

namespace thread_pool_module
{
    using namespace log_module;
    const size_t default_thread_count = 4;
    //任务类型
    //约定任务就是线程的回调方法
    //任务应该是无参无返回值的的调用对象
    template <class T>
    class thread_pool
    {
    private:
        //只指定线程数量
        thread_pool(size_t thread_count = default_thread_count)
            :_threads(thread_count)
            ,_wait_thread_count(0)
            ,_is_running(false)
        {
            LOG(LOG_LEVEL::INFO) << "thread_pool init";
        }
        //拷贝构造函数
        thread_pool(const thread_pool<T>&) = delete;
        //赋值构造函数
        thread_pool<T>& operator=(const thread_pool<T>&) = delete;


        //线程获取任务
        void thread_get_task()
        {
            //线程一直不停地获取任务
            while(true) 
            {
                std::unique_lock<std::mutex> lock(_mutex);
                while(_task_queue.empty() && _is_running)
                {
                    //等待任务
                    ++_wait_thread_count;
                    _condition.wait(lock);                    
                    --_wait_thread_count;
                }
                //线程池停止运行并且任务队列为空
                if(!_is_running && _task_queue.empty())
                {
                    return;
                }
                //获取任务
                T& task = _task_queue.front();
                _task_queue.pop();
                //执行任务
                LOG(LOG_LEVEL::INFO) << "thread_get_task, run task" << std::this_thread::get_id();
                task();
            }           
            
        }
    public:
        static thread_pool<T> &get_instance(size_t thread_count = default_thread_count)
        {
            static thread_pool<T> instance(thread_count);
            return instance;
        }

        //启动线程池
        void start()
        {   
            if(_is_running)
            {
                return;
            }
            _is_running = true;
            LOG(LOG_LEVEL::INFO) << "thread_pool start ";
            for(std::thread& t : _threads)
            {
                std::function<void()> f = std::bind(&thread_pool<T>::thread_get_task, this);
                t = std::thread(f);
            }
            
        }
        //添加任务
        void add_task(const T& task)
        {
            if(!_is_running)
            {   
                LOG(LOG_LEVEL::ERROR) << "thread_pool is not running";
                return;
            }
            _mutex.lock();
            _task_queue.push(task);
            if(_wait_thread_count > 0)
            {
                _condition.notify_one();
            }
            _mutex.unlock();
        }

        //等待线程池中的任务执行完毕
        void wait()
        {

            for(std::thread& t : _threads)
            {
                LOG(LOG_LEVEL::INFO) << "thread_pool wait " << t.get_id();
                t.join();
            }
        }


        //停止线程池
        void stop()
        {
            if(!_is_running)
            {
                LOG(LOG_LEVEL::ERROR) << "thread_pool is not running";
                return;
            }
            LOG(LOG_LEVEL::INFO) << "thread_pool stop";
            _is_running = false;
            _condition.notify_all();
        }
    private:
        std::vector<std::thread> _threads;
        std::queue<T> _task_queue;
        std::mutex _mutex;
        std::condition_variable _condition;     //表示线程池中是否有任务
        size_t _wait_thread_count;              //等待任务的线程数量
        bool _is_running;                       //线程池是否在运行
    };

}